
import os
import datetime
import requests
import json
import re
from database import SqliteSingleton
from database.user_info_table_methods import UserInfoTableMethods
from database.sms_time_slots_methods import SmsTimeSlotsMethods
from database.sms_methods import SmsMethods
from send_sms import SendSms
import logging
import pickle
from settings import ELITE_API_ACCOUNT, ELITE_API_PASSWORD

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)





class Singleton:
    _instances = None
    _session = None
    _instance_file = 'singleton_instance.pkl'
    _loaded_from_file = False

    def __new__(cls, *args, **kwargs):
        if not cls._instances:
            if os.path.exists(cls._instance_file):
                try:
                    with open(cls._instance_file, 'rb') as f:
                        cls._instances = pickle.load(f)
                    if not cls._loaded_from_file:
                        logger.info("Loaded instance from file")
                        cls._loaded_from_file = True
                except Exception as e:
                    logger.error(f"Failed to load instance from file: {e}")
                    cls._instances = super(Singleton, cls).__new__(cls, *args, **kwargs)
                    cls._session = requests.Session()
            else:
                cls._instances = super(Singleton, cls).__new__(cls, *args, **kwargs)
                cls._session = requests.Session()
        return cls._instances

    def __init__(self, *args, **kwargs):
        if not hasattr(self, '_initialized'):
            logger.info("init Singleton")
            self.login()
            self._initialized = True

    def login(self):
        url = "https://tea.elitetea.cn/admin.php?s=/Public/login.html"
        data = {
            "username": ELITE_API_ACCOUNT,
            "password": ELITE_API_PASSWORD
        }
        r = self._session.post(url, data=data)
        if r.status_code == 200:
            logger.info("Login successful")
            self.save_instance()
        else:
            logger.error("Login failed")

    def save_instance(self):
        with open(self._instance_file, 'wb') as f:
            pickle.dump(self, f)
        logger.info("Instance saved to file")





class EliteNotice:

    def __init__(self, device_sn = "S1230510016"):

        logger.info("------------------init EliteNotice-----------------")

        
        Singleton()._session

        self.device_sn = device_sn

        self.device_name = self.get_device_name() # 获取设备名称

        self.notify_personnel = self.get_notify_personnel() # 获取通知人员 {1:["18000000000", "13188888888"], 2:["18000000001", "13188888889"]}

        logger.info(f"通知人员：{self.notify_personnel}")


    # 获取 硬件状态

    def get_hardware_status(self):

        url = f"https://tea.elitetea.cn/admin.php?s=/Message/lists/mid/396/dev_id/{self.device_sn}.html"

        r = Singleton()._session.get(url)



        if "<title>欢迎您登录菁英茶吧</title>" in r.text:
            print("登录失败，请检查账号密码")
            Singleton().login()

        else:

            regex = f'<td>1</td><td>{self.device_sn}</td><td>(.*?)</td><td>(.*?)</td><td>(.*?)</td><td>(.*?)</td><td>(.*?)</td><td>(.*?)</td><td>(.*?)</td><td>(.*?)</td><td><a class="external" href="(.*?)">记录</a></td>'

            match = re.search(regex, r.text)
            # 净水箱水量	原水箱水量	净水TDS值	CF滤芯使用寿命	RO滤芯使用寿命	废水箱	滤水量	时间
            if match:
                info = {
                    "device_sn": self.device_sn,
                    "净水箱水量": match.group(1),
                    "原水箱水量": match.group(2),
                    "净水TDS值": match.group(3),
                    "CF滤芯使用寿命": match.group(4),
                    "RO滤芯使用寿命": match.group(5),
                    "废水箱": match.group(6),
                    "滤水量": match.group(7),
                    "时间": match.group(8),
                    "记录连接": match.group(9)
                }


                logger.info(f"获取{self.device_sn}硬件状态成功")
                logger.info(info)

                return info


            else:   
                
                logger.error(f"获取{self.device_sn}硬件状态失败")

    # 获取最近一条泡茶记录
    def get_last_tea_record(self):

        url = f"https://tea.elitetea.cn/admin.php?s=/Message/lists/mid/397/dev_id/{self.device_sn}.html"

        r = Singleton()._session.get(url)

        if "<title>欢迎您登录菁英茶吧</title>" in r.text:
            print("登录失败，请检查账号密码")
            Singleton().login()

        else:

            regex = f'td>1</td><td>{self.device_sn}</td><td>(.*?)</td><td>(.*?)</td><td>(.*?)</td><td>(.*?)</td><td>(.*?)</td><td>(.*?)</td><td>(.*?)</td><td>(.*?)</td>'

            # 序号	设备id	仓位	茶	茶的69码	茶的第几泡	茶的总泡数	用户ID	泡茶编号	时间
            matches = re.search(regex, r.text)

            if matches:
                info = {
                    "device_sn": self.device_sn,
                    "仓位": matches.group(1),
                    "茶": matches.group(2),

                    "茶的69码": matches.group(3),
                    "茶的第几泡": matches.group(4),
                    "茶的总泡数": matches.group(5),

                    "用户ID": matches.group(6),
                    "泡茶编号": matches.group(7),
                    "时间": matches.group(8)
                }

                logger.info(f"获取{self.device_sn}最近一条泡茶记录成功")
                logger.info(info)

                return info

            else:
                
                logger.error(f"获取{self.device_sn}最近一条泡茶记录失败")

    def get_device_name(self):


        url = f"https://tea.elitetea.cn/admin.php?s=/Message/lists/mid/260.html&dev_id={self.device_sn}"


        r = Singleton()._session.get(url)

        if "<title>欢迎您登录菁英茶吧</title>" in r.text:
            print("登录失败，请检查账号密码")
            Singleton().login()
            return self.device_sn

        else:
            # 序号	所属产品	名称	编号	软件版本	控制板版本	参数	会员	维修记录	在线状态	最后上线时间	IP	软件升级	控制板升级	操作

            regex = f'<td>1</td><td>菁英茶吧</td><td>(.*?)</td><td>{self.device_sn}</td>'


            # print(re.findall('<td>1</td><td>菁英茶吧</td>(.*?)<td>', r.text))
            match = re.search(regex, r.text)
            

            if match:
                device_name = match.group(1)
                if not device_name:
                    device_name = self.device_sn
                logger.info(f"获取{self.device_sn}设备名称成功:{device_name}")
                return device_name

            else:
                return self.device_sn
            

    def get_notify_personnel(self): # 获取通知人员

        with SqliteSingleton() as conn:

            cursor = conn.cursor()
            user_info_table_methods = UserInfoTableMethods(conn, cursor)

            notify_personnel = user_info_table_methods.select_user_info_by_device_sn(self.device_sn)

            result = {}
            for personnel in notify_personnel:

                phone_number = personnel["phone"]

                notification_types = json.loads(personnel["notification_type"])

                for notification_type in notification_types:

                    if not result.get(notification_type):
                        result[int(notification_type)] = [phone_number]
                    else:
                        result[int(notification_type)].append(phone_number)

            return result
    
    # 发送原水桶缺水通知
    def send_original_water_bucket_empty_notification(self):
        phones = self.notify_personnel.get(1, [])
        
        with SqliteSingleton() as conn:
            cursor = conn.cursor()
            sms_methods = SmsMethods(conn, cursor)

            if sms_methods.select_send_original_water_bucket_empty_notification(self.device_sn):

                logger.info("原水桶缺水提醒最近半小内已发送过")

                return
            for phone in phones:
            
                res = SendSms(phone, template_code='SMS_467585524', template_param={"name": self.device_name}).main()
                # def insert_sms_records(self, device_sn, name, phone, template_code, content, send_status):
                content = f"您好，茶吧机{self.device_name}原水桶已缺水，请尽快补充。"
                sms_methods.insert_sms_records(self.device_sn, "原水桶缺水", phone, "SMS_467585524", content, res)

    # 发送废水箱已满通知
    def send_waste_water_bucket_full_notification(self):
        phones = self.notify_personnel.get(2, [])
        
            
        with SqliteSingleton() as conn:
            cursor = conn.cursor()
            sms_methods = SmsMethods(conn, cursor)
            if sms_methods.select_send_waste_water_bucket_full_notification(self.device_sn):
                
                logger.info("废水箱已满提醒最近半小内已发送过")
                return
            for phone in phones:
                print(f"self.device_name:{self.device_name}, type:{type(self.device_name)}")
                res = SendSms(phone, template_code='SMS_467430469', template_param={"name": self.device_name}).main()
                # def insert_sms_records(self, device_sn, name, phone, template_code, content, send_status):
                content = f"您好，茶吧机{self.device_name}的废水箱已满，请尽快将废水箱清空。"
                sms_methods.insert_sms_records(self.device_sn, "废水箱已满", phone, "SMS_467430469", content, res) 

    # 发送最大泡次提醒
    def send_max_tea_times_notification(self, around, tea):
        phones = self.notify_personnel.get(3, [])
        temp_param = {"name": self.device_name, "around": around, "tea": tea}
        # for phone in phones:
        with SqliteSingleton() as conn:
            cursor = conn.cursor()
            sms_methods = SmsMethods(conn, cursor)
            if sms_methods.select_send_max_tea_times_notification(self.device_sn):
                
                logger.info("最大泡次提醒最近半小内已发送过")
                return
            
            for phone in phones:
                res = SendSms(phone, template_code='SMS_467385534', template_param=temp_param).main()
                # def insert_sms_records(self, device_sn, name, phone, template_code, content, send_status):
                content = f"您好，{self.device_name}茶吧机${around}侧的{tea}已达最大泡次，请尽快将泡茶仓清洗干净。"
                sms_methods.insert_sms_records(self.device_sn, "最大泡次提醒", phone, "SMS_467385534", content, res)

    # 发送滤芯快到期通知
    def send_filter_expires_soon_notification(self, filter, days):

        temp_param = {"name": self.device_name, "filter": filter, "days": days}
        phones = self.notify_personnel.get(4, [])
        
            
        with SqliteSingleton() as conn:
            cursor = conn.cursor()
            sms_methods = SmsMethods(conn, cursor)

            if sms_methods.select_send_filter_expires_soon_notification(self.device_sn):

                logger.info("滤芯快到期提醒最近3天内已发送过")
                return
            for phone in phones:
                res = SendSms(phone, template_code='SMS_467500556', template_param=temp_param).main()

                # def insert_sms_records(self, device_sn, name, phone, template_code, content, send_status):
                content = f"您好，{self.device_name}茶吧机的{filter}号滤芯还有${days}天即将到期，为了达到最佳泡茶口感，可联系客服或菁英茶微信小程序商城中进行购买。"
                sms_methods.insert_sms_records(self.device_sn, "滤芯快到期提醒", phone, "SMS_467500556", content, res)
    # 解析tea_record_url判断是否发送泡茶记录通知
    def send_tea_record_notification(self):
        '''info = {
                    "device_sn": self.device_sn,
                    "仓位": matches.group(1),
                    "茶": matches.group(2),

                    "茶的69码": matches.group(3),
                    "茶的第几泡": matches.group(4),
                    "茶的总泡数": matches.group(5),

                    "用户ID": matches.group(6),
                    "泡茶编号": matches.group(7),
                    "时间": matches.group(8)
                }'''
        last_tea_record = self.get_last_tea_record()
        if not last_tea_record:

            return
        
        with SqliteSingleton() as conn:
            cursor = conn.cursor()
            sms_methods = SmsMethods(conn, cursor)
            if not sms_methods.insert_tea_pots(self.device_sn, json.dumps(last_tea_record)):

                logger.info("泡茶记录已存在")
                return
        
        if last_tea_record["茶的第几泡"] >= last_tea_record["茶的总泡数"]:

            self.send_max_tea_times_notification(last_tea_record["仓位"], last_tea_record["茶"])

                    

    # 解析tea_record_url判断是否发送泡茶记录通知
    def send_hardware_status_notification(self):
        '''hardware_status = {
                    "device_sn": self.device_sn,
                    "净水箱水量": match.group(1),
                    "原水箱水量": match.group(2),
                    "净水TDS值": match.group(3),
                    "CF滤芯使用寿命": match.group(4),
                    "RO滤芯使用寿命": match.group(5),
                    "废水箱": match.group(6),
                    "滤水量": match.group(7),
                    "时间": match.group(8),
                    "记录连接": match.group(9)
                }'''
        hardware_status = self.get_hardware_status()

        if not hardware_status:

            return
        
        with SqliteSingleton() as conn:
            cursor = conn.cursor()
            sms_methods = SmsMethods(conn, cursor)
            if not sms_methods.insert_hardware_records(self.device_sn, json.dumps(hardware_status)):

                logger.info("硬件状态记录已存在")
                return

        

        if hardware_status["原水箱水量"] == "无水": 

            self.send_original_water_bucket_empty_notification()

        if hardware_status["废水箱"] == "高水位":

            self.send_waste_water_bucket_full_notification()

        if int(hardware_status["CF滤芯使用寿命"]) <= 10 :

            self.send_filter_expires_soon_notification("1", int((int(hardware_status["CF滤芯使用寿命"])) *1.8)  )
        
        elif int(hardware_status["RO滤芯使用寿命"]) <= 10:

            self.send_filter_expires_soon_notification("2", int((int(hardware_status["RO滤芯使用寿命"])) *1.8))

    @staticmethod
    def sms_time_slots_verify():
        now_time = datetime.datetime.now()
        now_time_str = now_time.strftime("%H:%M:%S")

        with SqliteSingleton() as conn:
            cursor = conn.cursor()
            time_slots_list = SmsTimeSlotsMethods(conn, cursor).select_sms_time_slots_by_status_active()

            for time_slot in time_slots_list:
                start_time_str = time_slot["start_time"]
                end_time_str = time_slot["end_time"]

                # 将字符串转换为 datetime 对象
                start_time = datetime.datetime.strptime(start_time_str, "%H:%M:%S")
                end_time = datetime.datetime.strptime(end_time_str, "%H:%M:%S")

                # 将当前时间转换为 HH:MM:SS 格式
                now_time_hhmmss = datetime.datetime.strptime(now_time_str, "%H:%M:%S")

                if start_time <= now_time_hhmmss <= end_time:
                    return True

        return False






if __name__ == '__main__':

    if EliteNotice.sms_time_slots_verify():

        with SqliteSingleton() as conn:
            cursor = conn.cursor()
            user_info_table_methods = UserInfoTableMethods(conn, cursor)


            device_sn_list = user_info_table_methods.select_device_sn_list()

            logger.info(f"device_sn_list:{device_sn_list}")

            for device_sn in device_sn_list:
                elite_notice = EliteNotice(device_sn=device_sn)
                elite_notice.send_tea_record_notification()
                elite_notice.send_hardware_status_notification()

    else:

        logger.info("不在发送时间段内")


